package com.winchain.chainbill.bill.biz.send.service.impl;

import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.MoneyUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.sequence.SequenceHelper;
import com.shell.customer.feign.CustomerFeign;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.MathsUtil;
import com.shell.framework.utils.ParameterHelper;
import com.shell.governor.modules.vo.ParameterVo;
import com.winchain.chainbill.basic.charge.service.ValComService;
import com.winchain.chainbill.basic.charge.vo.ValComVo;
import com.winchain.chainbill.basic.cus.po.CusGrp;
import com.winchain.chainbill.basic.cus.service.CusGrpService;
import com.winchain.chainbill.basic.cus.service.CusRecService;
import com.winchain.chainbill.bill.base.po.CbDct;
import com.winchain.chainbill.bill.base.po.CbDfrl;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.po.CbRpur;
import com.winchain.chainbill.bill.base.po.CbSnd;
import com.winchain.chainbill.bill.base.po.CbStats;
import com.winchain.chainbill.bill.base.po.CbXfe;
import com.winchain.chainbill.bill.base.service.CbSndService;
import com.winchain.chainbill.bill.biz.Bill;
import com.winchain.chainbill.bill.biz.send.service.BillService;
import com.winchain.chainbill.bill.biz.send.vo.BillSnd;
import com.winchain.chainbill.bill.biz.transfer.vo.BillXfe;
import com.winchain.chainbill.risk.utill.RateUtil;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("billService")
public class BillServiceImpl implements BillService {
	@Autowired
	private CusRecService basCusService;
	@Autowired
	private CustomerFeign customerFeign;
	@Autowired
	private CusGrpService cusGrpService;
	@Autowired
	private CbSndService cbSndService;
	@Autowired
	private ValComService valComService;

	public void init(CbRec bill, CbStats stats, CbSnd send) {
		String billId = bill.getBillId();
		if (StringUtil.emptyAndNull(billId)) {
			billId = SystemUtil.getUUID();
			bill.setBillState("S000");
			bill.setOptSeq(Integer.valueOf(-1));
			bill.setHldrLvl(Integer.valueOf(-1));
		}
		String billType = bill.getBillType();
		bill.setBillId(billId);

		String buyerId = CommonDataUtil.getCurEntId();
		String billCode = bill.getBillCode();
		if (StringUtil.emptyAndNull(billCode)) {
			billCode = getBillCode(buyerId, "R");
			bill.setBillCode(billCode);
		}
		bill.setRootId(billId);
		if ("1".equals(billType)) {
			ParameterVo sndNeedInterest = ParameterHelper.getCommonParameter("SND_NEED_INTEREST");
			if (sndNeedInterest.getParmValue().equals("1")) {
				String sndFixedRateStr = RateUtil.getFixedRate(bill.getGrpId(), bill.getFinId(), "snd_fixed_rate");
				String sndVariableRateStr = RateUtil.getVariableRate(bill.getGrpId(), bill.getFinId(),
						CommonDataUtil.getCurEntId(), "snd_variable_rate");
				BigDecimal sndFixedRate = new BigDecimal(sndFixedRateStr);
				BigDecimal sndVariableRate = new BigDecimal(sndVariableRateStr);
				send.setFixedRate(sndFixedRate);
				send.setVarRate(sndVariableRate);

				int days = DateUtil.getDaysBetween(bill.getSndDate(), bill.getExpDate());

				BigDecimal sndInt = MathsUtil.mathInterest(bill.getBillAmt(), sndFixedRate.add(sndVariableRate), days);
				send.setSndInt(sndInt);
			}
		}
		CusGrp grp = (CusGrp) this.cusGrpService.selectByKey(bill.getGrpId());
		bill.setGrpNm(grp.getGrpName());

		com.winchain.chainbill.basic.cus.po.CusRec fin = (com.winchain.chainbill.basic.cus.po.CusRec) this.basCusService
				.selectByKey(bill.getFinId());
		bill.setFinNm(fin.getCusName());
		if ("1".equals(grp.getConfirmerType())) {
			bill.setConfirmerId(send.getBuyerId());
			bill.setConfirmerNm(send.getBuyerNm());
		} else {
			List<com.shell.customer.po.CusRec> recs = this.customerFeign.getCusyGroupIdAndTagCodes(bill.getGrpId(),
					"CONFIRMER");
			if ((recs != null) && (recs.size() > 0)) {
				bill.setConfirmerId(((com.shell.customer.po.CusRec) recs.get(0)).getCusId());
				bill.setConfirmerNm(((com.shell.customer.po.CusRec) recs.get(0)).getCusName());
			}
		}
		stats.setBillId(billId);
		stats.setChdNum(Integer.valueOf(0));
		stats.setXfeFreq(Integer.valueOf(0));
		stats.setDctAmt(new BigDecimal("0"));
		if (StringUtil.emptyAndNull(send.getSndId())) {
			send.setSndId(SystemUtil.getUUID());
		}
		send.setBillId(billId);
		send.setExpDate(bill.getExpDate());

		send.setBuyerId(buyerId);
		send.setBuyerNm(CommonDataUtil.getCurEntName());
		send.setSndState("0");
		send.setBailState("0");
		send.setCreateTime(DateUtil.getSystemDateTime());
	}

	public String getBillCode(String buyerId, String billCls) {
		String cusCode = ((com.winchain.chainbill.basic.cus.po.CusRec) this.basCusService.selectByKey(buyerId))
				.getCusCode();

		StringBuilder builder = new StringBuilder(billCls);
		builder.append(getFormativeCusCode(cusCode));
		builder.append(DateUtil.getSystemDate());
		builder.append(getSerialNo(cusCode));
		return builder.toString();
	}

	private String getFormativeCusCode(String cusCode) {
		return cusCode;
	}

	private String getSerialNo(String cusCode) {
		return SequenceHelper.generateCode(cusCode, 5);
	}

	public List<BillXfe> init(CbRec record, CbXfe... xfes) {
		List<BillXfe> bills = new ArrayList();
		BigDecimal prntAmt = record.getBillAmt();
		BigDecimal billAmt = record.getBillAmt();
		BigDecimal xfeMoney = null;
		CbRec chd = null;

		BillXfe bill = null;
		for (CbXfe xfe : xfes) {
			xfeMoney = xfe.getBillAmt();
			if (prntAmt.compareTo(xfeMoney) == 0) {
				chd = record;
				init(record, chd, xfe);
				billAmt = new BigDecimal(0);
			} else {
				chd = new CbRec();
				init(record, chd, xfe);
				billAmt = billAmt.subtract(xfeMoney);
			}
			bill = new BillXfe();
			bill.setRec(chd);

			bill.setSource(xfe);

			CbDfrl dfrl = initDfr(record, xfe);
			bill.setDfrl(dfrl);

			bills.add(bill);
		}
		if (billAmt.compareTo(new BigDecimal(0)) == 1) {
			chd = new CbRec();
			chd.setBillAmt(billAmt);
			init(record, chd, null);

			bill = new BillXfe();
			bill.setRec(chd);

			bill.setSource(null);

			chd.setOptSeq(Integer.valueOf(-1));
			chd.setHldrLvl(Integer.valueOf(record.getHldrLvl().intValue() - 1));

			bills.add(bill);
		}
		return bills;
	}

	private void init(CbRec prnt, CbRec chd, CbXfe xfe) {
		String buyerId = CommonDataUtil.getCurEntId();
		String buyerName = CommonDataUtil.getCurEntName();

		String chdBillId = chd.getBillId();
		if (StringUtil.emptyAndNull(chdBillId)) {
			chd.setBillId(SystemUtil.getUUID());
			chd.setBillState("S000");

			String billCode = getBillCode(buyerId, "N");
			chd.setBillCode(billCode);
			chd.setBillType(prnt.getBillType());
			chd.setRootId(prnt.getRootId());
			chd.setPrntId(prnt.getBillId());
			chd.setSndDate(prnt.getSndDate());
			chd.setExpDate(prnt.getExpDate());

			chd.setOptSeq(Integer.valueOf(-1));
			chd.setHldrLvl(prnt.getHldrLvl());

			chd.setFinId(prnt.getFinId());
			chd.setFinNm(prnt.getFinNm());

			chd.setConfirmerId(prnt.getConfirmerId());
			chd.setConfirmerNm(prnt.getConfirmerNm());

			chd.setGrpId(prnt.getGrpId());
			chd.setGrpNm(prnt.getGrpNm());
			if (xfe != null) {
				chd.setBillAmt(xfe.getBillAmt());
			}
		}
		if (xfe != null) {
			xfe.setXfeId(SystemUtil.getUUID());
			xfe.setBillId(chd.getBillId());
			xfe.setPrntId(prnt.getBillId());
			xfe.setBuyerId(buyerId);
			xfe.setBuyerNm(buyerName);
			xfe.setXfeState("1");
			xfe.setHldrLvl(Integer.valueOf(chd.getHldrLvl().intValue() + 1));
			xfe.setCreateTime(DateUtil.getSystemDateTime());
		}
	}

	private CbDfrl initDfr(CbRec record, CbXfe xfe) {
		CbDfrl cbDfrl = new CbDfrl();
		cbDfrl.setDfrlId(SystemUtil.getUUID());
		cbDfrl.setXfeId(xfe.getXfeId());
		cbDfrl.setPreExpDate(record.getExpDate());
		cbDfrl.setExpDate(xfe.getExpDate());
		cbDfrl.setBillId(xfe.getBillId());
		cbDfrl.setCreateTime(DateUtil.getSystemDateTime());

		int days = DateUtil.getDaysBetween(cbDfrl.getPreExpDate(), cbDfrl.getExpDate());
		if (days == 0) {
			return null;
		}
		if (days > 0) {
			cbDfrl.setDeferred("1");
		}
		cbDfrl.setDfrlState("0");

		String grpId = record.getGrpId();
		String dfrRate = RateUtil.getRateByCode("financing_rate", "3", grpId, grpId, grpId);
		cbDfrl.setDfrRate(new BigDecimal(dfrRate));
		BigDecimal dfrInt = MathsUtil.mathInterest(xfe.getBillAmt(), new BigDecimal(dfrRate), days);
		cbDfrl.setDfrInt(dfrInt);
		return cbDfrl;
	}

	private void initSell(CbRec prnt, CbRec chd, CbDct sell) {
		String sellerId = CommonDataUtil.getCurEntId();
		String sellerName = CommonDataUtil.getCurEntName();

		String chdBillId = chd.getBillId();
		if (StringUtil.emptyAndNull(chdBillId)) {
			chd.setBillId(SystemUtil.getUUID());
			chd.setBillState("S000");

			String billCode = getBillCode(sellerId, "N");
			chd.setBillCode(billCode);
			chd.setBillType(prnt.getBillType());
			chd.setRootId(prnt.getRootId());
			chd.setPrntId(prnt.getBillId());
			chd.setSndDate(prnt.getSndDate());
			chd.setExpDate(prnt.getExpDate());

			chd.setOptSeq(Integer.valueOf(-1));
			chd.setHldrLvl(prnt.getHldrLvl());
			chd.setFinId(prnt.getFinId());
			chd.setFinNm(prnt.getFinNm());
			chd.setConfirmerId(prnt.getConfirmerId());
			chd.setConfirmerNm(prnt.getConfirmerNm());
			chd.setGrpId(prnt.getGrpId());
			chd.setGrpNm(prnt.getGrpNm());
			if (sell != null) {
				chd.setBillAmt(sell.getDctAmt());
			}
		}
		if (sell != null) {
			sell.setDctId(SystemUtil.getUUID());
			sell.setBillId(chd.getBillId());
			sell.setPrntId(prnt.getBillId());
			sell.setSellerId(sellerId);
			sell.setSellerNm(sellerName);
			sell.setDctState("1");
			sell.setHldrLvl(Integer.valueOf(chd.getHldrLvl().intValue() + 1));
			sell.setCreatorId(CommonDataUtil.getUserId());
			sell.setCreateTime(DateUtil.getSystemDateTime());
			sell.setPmtState("0");
			sell.setExpDate(prnt.getExpDate());
			sell.setDctDays(Integer.valueOf(DateUtil.getDaysBetween(sell.getDctDate(), prnt.getExpDate())));

			String buyerId = sell.getFinId();
			String buyerNm = sell.getFinNm();

			ValComVo serviceFee = this.valComService.getDctValComVo(sell.getFinId(), prnt.getGrpId());
			if ((serviceFee != null) && ("1".equals(serviceFee.getPayBy()))) {
				buyerId = sell.getSellerId();
				buyerNm = sell.getSellerNm();
			}
			sell.setBuyerId(buyerId);
			sell.setBuyerNm(buyerNm);

			String senderId = this.cbSndService.getBillSndById(prnt.getRootId()).getBuyerId();

			ParameterVo dctNeedInterest = ParameterHelper.getCommonParameter("DCT_NEED_INTEREST");

			String dctRatio = RateUtil.getEntDctRate(prnt.getGrpId(), prnt.getGrpId(), senderId, "ent_tb_dct_rate");
			if (StringUtil.emptyAndNull(dctRatio)) {
				dctRatio = RateUtil.getDctRate(sell.getFinId(), sell.getFinId(), sell.getFinId(), "tb_dct_rate");
			}
			BigDecimal dctAmtWithRatio = sell.getDctAmt();
			if (StringUtil.emptyAndNull(dctRatio)) {
				sell.setDctRatio(BigDecimal.ZERO);
			} else {
				sell.setDctRatio(new BigDecimal(dctRatio));
				dctAmtWithRatio = dctAmtWithRatio.multiply(sell.getDctRatio()).divide(MoneyUtil.HUNDRED, 2,
						RoundingMode.HALF_UP);
			}
			if ((dctNeedInterest != null) && (dctNeedInterest.getParmValue().equals("1"))) {
				String dctFixedRate = RateUtil.getFixedRate(prnt.getGrpId(), sell.getFinId(), "dct_fixed_rate");
				String dctVariableRate = RateUtil.getVariableRate(prnt.getGrpId(), sell.getFinId(), senderId,
						"dct_variable_rate");
				String dctEntVariableRate = RateUtil.getEntVariableRate(prnt.getGrpId(), prnt.getGrpId(),
						CommonDataUtil.getCurEntId(), "dct_ent_variable_rate");
				String dctEntVariableRateFin = RateUtil.getEntVariableRate(prnt.getGrpId(), sell.getFinId(),
						CommonDataUtil.getCurEntId(), "dct_ent_variable_rate");
				if (StringUtil.empty(dctEntVariableRate)) {
					dctEntVariableRate = dctEntVariableRateFin;
				}
				if (StringUtil.empty(dctFixedRate)) {
					dctFixedRate = "0";
				}
				if (StringUtil.empty(dctVariableRate)) {
					dctVariableRate = "0";
				}
				if (StringUtil.empty(dctEntVariableRate)) {
					dctEntVariableRate = "0";
				}
				BigDecimal fr = new BigDecimal(dctFixedRate);
				BigDecimal vr = new BigDecimal(dctVariableRate);
				BigDecimal evr = new BigDecimal(dctEntVariableRate);
				sell.setFixedRate(fr);
				sell.setVarRate(vr);
				sell.setEntVarRate(evr);

				ParameterVo rateMParam = ParameterHelper.getParameter("6", "DCT_RATE_MODE", prnt.getGrpId());

				BigDecimal sellInt = MathsUtil.mathDctInterest(dctAmtWithRatio, fr.add(vr).add(evr),
						sell.getDctDays().longValue(), rateMParam.getParmValue());
				if ((rateMParam == null) || (StringUtil.emptyAndNull(rateMParam.getParmValue()))) {
					sell.setRateMode("2");
				} else {
					sell.setRateMode(rateMParam.getParmValue());
				}
				ParameterVo minIntPar = ParameterHelper.getParameter("6", "DCT_MIN_INT", prnt.getGrpId());
				if ((minIntPar != null) && (!StringUtil.emptyAndNull(minIntPar.getParmValue()))) {
					BigDecimal minInt = new BigDecimal(minIntPar.getParmValue());
					if (sellInt.compareTo(minInt) < 0) {
						sell.setDctInt(minInt);
					} else {
						sell.setDctInt(sellInt);
					}
				} else {
					sell.setDctInt(sellInt);
				}
				sell.setDeductInt(BigDecimal.ZERO);
			} else {
				sell.setFixedRate(BigDecimal.ZERO);
				sell.setVarRate(BigDecimal.ZERO);
				sell.setDctInt(BigDecimal.ZERO);
				sell.setDeductInt(BigDecimal.ZERO);
			}
			BigDecimal actualAmt = dctAmtWithRatio.subtract(sell.getDctInt());
			if (!MoneyUtil.biggerThanZero(actualAmt)) {
				throw new UnCheckMsgException("��������������������0");
			}
		}
	}

	public List<Bill<CbDct>> init(CbRec record, CbDct... sells) {
		List<Bill<CbDct>> bills = new ArrayList();
		BigDecimal billAmt = record.getBillAmt();
		BigDecimal sellMoney = null;
		CbRec chd = null;

		Bill<CbDct> bill = null;
		for (CbDct sell : sells) {
			sellMoney = sell.getDctAmt();
			if (billAmt.compareTo(sellMoney) == 0) {
				chd = record;
				initSell(record, chd, sell);
				billAmt = new BigDecimal(0);
			} else {
				chd = new CbRec();
				initSell(record, chd, sell);
				billAmt = billAmt.subtract(sellMoney);
			}
			bill = new Bill();
			bill.setRec(chd);

			bill.setSource(sell);

			bills.add(bill);
		}
		if (billAmt.compareTo(new BigDecimal(0)) == 1) {
			chd = new CbRec();
			chd.setBillAmt(billAmt);
			initSell(record, chd, null);

			bill = new Bill();
			bill.setRec(chd);

			bill.setSource(null);

			chd.setOptSeq(Integer.valueOf(-1));
			chd.setHldrLvl(Integer.valueOf(record.getHldrLvl().intValue() - 1));

			bills.add(bill);
		}
		return bills;
	}

	public Bill<CbRpur> init(CbRec record, CbDct sell, CbRpur buy) {
		Bill<CbRpur> bill = new Bill();
		buy.setRpurId(SystemUtil.getUUID());

		buy.setBuyerId(sell.getSellerId());
		buy.setBuyerNm(sell.getSellerNm());

		int days = DateUtil.getDaysBetween(DateUtil.getSystemDate(), record.getExpDate());

		String senderId = this.cbSndService.getBillSndById(record.getRootId()).getBuyerId();
		String rpurFixedRateStr = RateUtil.getFixedRate(record.getGrpId(), sell.getFinId(), "rpur_fixed_rate");
		String rpurVariableRateStr = RateUtil.getVariableRate(record.getGrpId(), sell.getFinId(), senderId,
				"rpur_variable_rate");
		String rpurEntVariableRateStr = RateUtil.getEntVariableRate(record.getGrpId(), record.getGrpId(),
				CommonDataUtil.getCurEntId(), "rpur_ent_variable_rate");
		String rpurEntVariableRateFinStr = RateUtil.getEntVariableRate(record.getGrpId(), sell.getFinId(),
				CommonDataUtil.getCurEntId(), "rpur_ent_variable_rate");
		if (StringUtil.empty(rpurEntVariableRateStr)) {
			rpurEntVariableRateStr = rpurEntVariableRateFinStr;
		}
		if (StringUtil.empty(rpurFixedRateStr)) {
			rpurFixedRateStr = "0";
		}
		if (StringUtil.empty(rpurVariableRateStr)) {
			rpurVariableRateStr = "0";
		}
		if (StringUtil.empty(rpurEntVariableRateStr)) {
			rpurEntVariableRateStr = "0";
		}
		BigDecimal rpurFixedRate = new BigDecimal(rpurFixedRateStr);
		BigDecimal rpurVariableRate = new BigDecimal(rpurVariableRateStr);
		BigDecimal rpurEntVariableRate = new BigDecimal(rpurEntVariableRateStr);

		BigDecimal rpurInt = MathsUtil.mathInterest(sell.getDctAmt(),
				rpurFixedRate.add(rpurVariableRate).add(rpurEntVariableRate), days);

		buy.setRpurDays(Integer.valueOf(days));
		buy.setRpurInt(rpurInt);
		buy.setRpurAmt(sell.getDctAmt());
		buy.setRpurState("1");
		buy.setCreateTime(DateUtil.getSystemDateTime());
		buy.setExpDate(record.getExpDate());
		buy.setFixedRate(rpurFixedRate);
		buy.setOptSeq(Integer.valueOf(0));
		buy.setRpurId(sell.getDctId());
		buy.setVarRate(rpurVariableRate);
		buy.setEntVarRate(rpurEntVariableRate);
		buy.setHldrLvl(Integer.valueOf(record.getHldrLvl().intValue() + 1));

		bill.setSource(buy);
		bill.setRec(record);

		return bill;
	}
}
